﻿using System;
using System.Collections.Generic;
using System.Linq;
using Chambills.Present.Core;
using Chambills.Present.Core.NotifyOnChange;

namespace Chambills.Present.Validation
{
    public class DefaultViewModelValidator : NotifiableObject
    {
        private readonly IList<IViewModelValidationContributor> contributors;
        private readonly BrokenBindingContributor brokenBindingContributor;
        private IViewModel model;
        private bool enabled;

        public DefaultViewModelValidator(params IViewModelValidationContributor[] contributors)
        {
            brokenBindingContributor = new BrokenBindingContributor();
            this.contributors = new List<IViewModelValidationContributor>(contributors ?? new IViewModelValidationContributor[0])
                                    {
                                        brokenBindingContributor
                                    };
            Model = null;
        }

        /// <summary>
        /// If disabled, will be empty
        /// </summary>
        /// <returns></returns>
        private IEnumerable<IViewModelValidationContributor> GetContributors()
        {
            return Enabled ? contributors : new IViewModelValidationContributor[0];
        }

        public IViewModel Model
        {
            get
            {
                return model;
            }
            set
            {
                model = value;
                contributors.ForEach(x => x.Model = model);
            }
        }

        /// <summary>
        /// Returns errors for the given property
        /// </summary>
        public string this[string columnName]
        {
            get
            {
                var errors = FormatErrors(GetErrorsForProperty(columnName));
                OnPropertyChanged(() => Error);
                return errors;
            }
        }

       

        /// <summary>
        /// Newline seperated list of errors for the View Model
        /// </summary>
        public virtual string Error
        {
            get
            {
                return FormatErrors(GetCurrentErrors());
            }
        }

        public List<string> GetCurrentErrors()
        {
            return GetContributors().SelectMany(x => x.GetCurrentErrors()).ToList();
        }

        private List<string> GetErrorsForProperty(string propertyName)
        {
            return GetContributors().SelectMany(x => x.GetErrorsForProperty(propertyName)).ToList();
        }


        private string FormatErrors(List<string> errorsToJoin)
        {
            errorsToJoin.RemoveAll(String.IsNullOrEmpty);
            return string.Join(Environment.NewLine, errorsToJoin.ToArray());
        }
        
        
        /// <summary>
        /// Bind to a <see cref="BrokenBindingNotifier"/> in your view
        /// Do not set manually
        /// <example>
        /// <Validation:BrokenBindingNotifier PropertiesWithBrokenBindings="{Binding PropertiesWithBrokenBindings, Mode=OneWayToSource}" />
        /// </example>
        /// </summary>
        public List<string> BrokenBindings
        {
            get { return brokenBindingContributor.BrokenBindings; }
            set { brokenBindingContributor.BrokenBindings = value; }
        }

        public bool IsValid
        {
            get { return GetCurrentErrors().IsEmpty(); }
            
        }

        public bool Enabled
        {
            get { return enabled; }
            set
            {
                enabled = value;
                OnPropertyChanged(() => Enabled);
            }
        }
    }
}
